import 'dart:collection';

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:share_fit/app/controllers/base/base_controller.dart';
import 'package:share_fit/app/helper/db/ute_db_helper.dart';
import 'package:share_fit/app/helper/ext/tr_ext.dart';
import 'package:share_fit/app/models/home/date_type_enum.dart';
import 'package:share_fit/app/models/home/heart_rate_model.dart';
import 'package:share_fit/app/tools/locale_tool.dart';
import 'package:share_fit/app/tools/date_tool.dart';
import 'package:share_fit/generated/locales.g.dart';

import 'state.dart';

class HeartRateLogic extends BaseController {
  final HeartRatesState state = HeartRatesState();

  changeDateType({type, int? selectedIndex}) {
    state.selectedDateType.value = type;
    state.dateTypeBarIndex = selectedIndex ?? 0;
    update();

    if (type == DateType.year) {
      for (var month = 1; month <= 12; month++) {
        // state.dates.add('$month');
      }
    } else if (type == DateType.week) {
      List<DateTime> dts = type.getWeekDays;
      _queryInRange(dts.first, dts.last, true);
      _findAvg(dts.first, dts.last);
    } else if (type == DateType.month) {
      List<DateTime> dts = type.getMonthDays;
      _queryInRange(dts.first, dts.last, false);
      _findAvg(dts.first, dts.last);
    } else {
      // DateTime day = DateTool.isSameDay(state.selectedDate, type.getToday) ? type.getToday : state.selectedDate;
      DateTime day = state.selectedDate;
      queryTodayInMinuteData(day);
      _findAvg(day, day);
    }

    _getSummaryHR();

    update(['hr_avg_line_bar', 'calendar_btn_icon', 'date_type_bar']);
  }

  /// 右上角日历选择
  datePicker(dt) {
    if (dt != null) {
      state.selectedDate = dt;
      update(['calendar_btn_icon', 'hr_avg_line_bar']);

      queryTodayInMinuteData(dt);
      _getSummaryHR(date: dt);
      _findAvg(dt, dt);
    }
  }

  String getAvgIndicatorText() {
    if (state.selectedDateType.value == DateType.day) {
      return LocaleKeys.hr_day_avg_title.ts;
    } else if (state.selectedDateType.value == DateType.week) {
      return LocaleKeys.hr_week_avg_title.ts;
    } else if (state.selectedDateType.value == DateType.month) {
      return LocaleKeys.hr_month_avg_title.ts;
    } else {
      return LocaleKeys.hr_year_avg_title.ts;
    }
  }

  String getMaxIndicatorText() {
    if (state.selectedDateType.value == DateType.day) {
      return LocaleKeys.hr_day_max_title.ts;
    } else if (state.selectedDateType.value == DateType.week) {
      return LocaleKeys.hr_week_max_title.ts;
    } else if (state.selectedDateType.value == DateType.month) {
      return LocaleKeys.hr_month_max_title.ts;
    } else {
      return LocaleKeys.hr_year_max_title.ts;
    }
  }

  String getMinIndicatorText() {
    if (state.selectedDateType.value == DateType.day) {
      return LocaleKeys.hr_day_min_title.ts;
    } else if (state.selectedDateType.value == DateType.week) {
      return LocaleKeys.hr_week_min_title.ts;
    } else if (state.selectedDateType.value == DateType.month) {
      return LocaleKeys.hr_month_min_title.ts;
    } else {
      return LocaleKeys.hr_year_min_title.ts;
    }
  }

  String getAvgBarTitle() {
    if (state.selectedDateType.value == DateType.day) {
      return LocaleKeys.hr_day_avg_bar_title.ts;
    } else if (state.selectedDateType.value == DateType.week) {
      return LocaleKeys.hr_week_avg_bar_title.ts;
    } else if (state.selectedDateType.value == DateType.month) {
      return LocaleKeys.hr_month_avg_bar_title.ts;
    } else {
      return LocaleKeys.hr_year_avg_bar_title.ts;
    }
  }

  String getCycleRatioTitle() {
    if (state.selectedDateType.value == DateType.week) {
      return LocaleKeys.hr_week_cycle_ratio_bar_title.ts;
    } else if (state.selectedDateType.value == DateType.month) {
      return LocaleKeys.hr_month_cycle_ratio_bar_title.ts;
    } else {
      return LocaleKeys.hr_year_cycle_ratio_bar_title.ts;
    }
  }

  void _updateDateRange({DateTime? start, required DateTime end}) {
    if (start == null) {
      state.dateRangeText = DateTool.ymdFormat(end);
    } else {
      state.dateRangeText = '${DateTool.ymdFormat(start)} ~ ${DateTool.ymdFormat(end)}';
    }
    update(['sleep_date_range']);
  }

  void fillList(list) {
    if (list.length == 1) {
      HRSummary temp = list.first;
      DateTime dt = DateTime.parse(temp.calendarTime);
      String start = DateTool.getYMDHMWithDash(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute - 1, 0));
      list.insert(0, HRSummary(heartRateAvg: 0, calendarTime: start, calendar: start.split(' ')[1]));
    }
  }

  Future<void> queryTodayInMinuteData(DateTime today) async {

    _updateDateRange(start: null, end: today);

    UteDbHelper.getDB().then((db) => //
        db.heartRateDao.findAllBy(getAddress(), DateTool.getYMDStr(today)).then((result) {
          List<HRSummary> summaryList = [];
          for (var res in result) {
            HRSummary summary = HRSummary.from(res);
            summary.calendar = res.calendarTime!.split(' ')[1];
            summaryList.add(summary);
          }

          fillList(summaryList);

          HRSummary hrs = HRSummary();
          hrs.heartRates = summaryList;
          state.hrAvgList = hrs;

          update(['hr_avg_chart']);
        }));
  }

  Future<void> _queryInRange(DateTime start, DateTime end, bool isWeek) async {

    _updateDateRange(start: start, end: end);

    final db = await UteDbHelper.getDB();
    List<HeartRateModel> result = await db.heartRateDao.findInRange(getAddress(), DateTool.getYMDStr(start), DateTool.getYMDStr(end));

    List<HRSummary> summaryList = [];

    if (result.isNotEmpty) {
      String langCode = LocaleTool.locale.split('_')[0];
      int days = end.difference(start).inDays;
      for (int i = 0; i <= days; i++) {
        DateTime temp = start.add(Duration(days: i));

        String calendar = isWeek ? DateFormat.E(langCode).format(temp) : DateTool.mdFormat(temp);

        List<HeartRateModel> matched = result.where((e) => DateTime.parse(e.calendar!).isAtSameMomentAs(temp)).toList();
        if (matched.isNotEmpty) {
          HRSummary hrs = HRSummary.from(matched[0]);
          hrs.calendar = calendar;
          hrs.calendarTime = DateFormat.yMMMd(langCode).format(temp);
          summaryList.add(hrs);
        } else {
          summaryList.add(HRSummary(calendar: calendar, calendarTime: DateFormat.yMMMd(langCode).format(temp)));
        }
      }
    }

    HRSummary hrs = HRSummary();
    hrs.heartRates = summaryList;
    state.hrAvgList = hrs;

    update(['hr_avg_chart']);
  }

  /// 日、周、月下面的心率显示，日显示最新一条心率记录中的平均心率，周、月显示周月的平均心率
  Future<void> _getSummaryHR({DateTime? date}) async {
    if (DateType.day == state.selectedDateType.value) {
      UteDbHelper.getDB().then((db) => //
          db.heartRateDao.findLatestOne(getAddress(), DateTool.getYMDStr(date ?? DateTime.now())).then((result) {
            state.currentHR = result == null ? '--' : '${result.heartRateAvg}';
            update(['hr_summary']);
          }));
    } else {
      state.currentHR = '${state.hrAvg.heartRateAvg}';
      update(['hr_summary']);
    }
  }

  /// 获取指定时间范围内的一条记录，获取最高心率、最低心率、平均心率
  Future<void> _findAvg(DateTime start, DateTime end) async {
    UteDbHelper.getDB().then((db) => //
        db.heartRateDao.findAvg(getAddress(), DateTool.getYMDStr(start), DateTool.getYMDStr(end)).then((result) {
          state.hrAvg = HRSummary.from(result ?? HeartRateModel());
          update(['hr_avg', 'hr_avg_line_bar']);
        }));
  }

  @override
  String getRemotePath() {
    return '';
  }

  @override
  void initState() {
    DateTime now = DateTime.now();
    queryTodayInMinuteData(now);
    _getSummaryHR();
    _findAvg(now, now);
    _loadDateListOfRecord();
  }

  @override
  void onRemoteEvent(event, method) {
    // TODO: implement onRemoteEvent
  }

  /// 将有心率数据的日期标记在日历上
  onCalendarEventLoad(DateTime day) {
    Map<DateTime, List<bool>> events = LinkedHashMap<DateTime, List<bool>>(
      equals: DateTool.isSameDay,
      hashCode: (key) => key.day * 1000000 + key.month * 10000 + key.year,
    )..addAll(state.dateListOfRecord);

    return events[day] ?? [];
  }

  /// 查找指定年份中有心率记录的日期
  Future<void> _loadDateListOfRecord() async {
    DateTime now = DateTime.now();
    DateTime lastYear = DateUtils.addMonthsToMonthDate(now, -12);
    UteDbHelper.getDB().then((db) => //
        db.heartRateDao.findHasRecordDays(getAddress(), lastYear.year.toString(), now.year.toString()).then((result) {
          state.dateListOfRecord.clear();
          result.forEach((element) {
            state.dateListOfRecord.putIfAbsent(DateTime.parse(element), () => [true]);
          });
        }));
  }
}
